package com.dopeydev.testcar;

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.location.Location;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;

import com.dopeydev.broadcast.FragmentManagerBroadcast;
import com.dopeydev.broadcast.PersonalBasesBroadcast;
import com.dopeydev.geofence.ReceiveTransitionsIntentService;
import com.dopeydev.geofence.SimpleGeofence;
import com.dopeydev.geofence.SimpleGeofenceStore;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesClient;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.LocationClient;
import com.google.android.gms.location.LocationClient.OnAddGeofencesResultListener;
import com.google.android.gms.location.LocationClient.OnRemoveGeofencesResultListener;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationStatusCodes;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;

public class MainActivity extends Activity implements
		GooglePlayServicesClient.ConnectionCallbacks,
		GooglePlayServicesClient.OnConnectionFailedListener, LocationListener,
		OnAddGeofencesResultListener, OnRemoveGeofencesResultListener {

	private final static int OFFSET = 120;
	private final static int DEFAULT_GEOFENCE_RADIUS = 200;
	private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;
	private static final int MILLISECONDS_PER_SECOND = 1000;
	public static final int UPDATE_INTERVAL_IN_SECONDS = 15;
	private static final long UPDATE_INTERVAL = MILLISECONDS_PER_SECOND
			* UPDATE_INTERVAL_IN_SECONDS;
	private static final int FASTEST_INTERVAL_IN_SECONDS = 60;
	private static final long FASTEST_INTERVAL = MILLISECONDS_PER_SECOND
			* FASTEST_INTERVAL_IN_SECONDS;

	private static final String TAG = "MainActivity";
	private LocationClient mLocationClient;
	private LocationRequest mLocationRequest;
	private boolean mConnected;
	private BroadcastReceiver mNetworkReceiver;
	private Location mLocation;

	private PersonalBasesBroadcast mPersonalBasesBroadcast = new PersonalBasesBroadcast() {

		@Override
		public void enteredLocation() {
			SharedPreferences pref = PreferenceManager
					.getDefaultSharedPreferences(getBaseContext());
			showToast("Entered Location " + pref.getInt("latitude", 0) + " - "
					+ pref.getInt("longitude", 0), Toast.LENGTH_LONG);
		}

	};

	private FragmentManagerBroadcast mFragmentManagerBroadcast = new FragmentManagerBroadcast() {

		@Override
		public void locationAcquired() {

			if (getFragmentManager().findFragmentById(R.id.containerOverlay) != null) {
				if (getFragmentManager().findFragmentByTag(
						ButtonTestFragment.TAG) != null) {
					getFragmentManager()
							.beginTransaction()
							.remove(getFragmentManager().findFragmentByTag(
									ButtonTestFragment.TAG)).commit();
				}
			}
		}

		@Override
		public void zoomToLocation(LatLng currentLocation) {
			setSavedPark(currentLocation);
		}

	};
	private MapViewFragment mMapFrag;
	private SimpleGeofenceStore mGeofenceStorage;
	private ArrayList<Geofence> mCurrentGeofences;

	// TODO: check for long -> int
	private void setSavedPark(LatLng currentLocation) {
		int latitude = (int) currentLocation.latitude;
		int longitude = (int) currentLocation.longitude;

		SharedPreferences pref = PreferenceManager
				.getDefaultSharedPreferences(getBaseContext());

		Editor editor;
		editor = pref.edit();

		editor.putInt("latitude", latitude);
		editor.putInt("longitude", longitude);

		editor.commit();

	}

	private LatLng getSavedPark() {

		SharedPreferences pref = PreferenceManager
				.getDefaultSharedPreferences(getBaseContext());

		int latitude;
		int longitude;
		// if (pref.getInt("latitude", 0) > 0) {
		latitude = pref.getInt("latitude", 0);
		// }
		// if (pref.getInt("longitude", 0) > 0) {
		longitude = pref.getInt("longitude", 0);
		// }

		LatLng lastSavedPark = new LatLng(latitude, longitude);

		return lastSavedPark;
	}

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		getActionBar().hide();
		// if (savedInstanceState == null) {
		// getFragmentManager().beginTransaction()
		// .add(R.id.container, new PlaceholderFragment()).commit();
		// }

		// Instantiate a new geofence storage area
		mGeofenceStorage = new SimpleGeofenceStore(this);
		mCurrentGeofences = new ArrayList<Geofence>();

		gpsManager();

		servicesConnected();

		FragmentManager fm = getFragmentManager();
		FragmentTransaction ft = fm.beginTransaction();

		mMapFrag = MapViewFragment.getInstance();
		ft.replace(R.id.containerMap, mMapFrag, MapViewFragment.TAG);

		// ButtonTestFragment overlayFrag = ButtonTestFragment.getInstance();
		// ft.replace(R.id.containerOverlay, overlayFrag,
		// ButtonTestFragment.TAG);

		ft.commit();
	}

	private boolean servicesConnected() {
		// Check that Google Play services is available
		int resultCode = GooglePlayServicesUtil
				.isGooglePlayServicesAvailable(this);
		// If Google Play services is available
		if (ConnectionResult.SUCCESS == resultCode) {
			// In debug mode, log the status
			Log.d("Geofence Detection", "Google Play services is available.");
			// Continue
			return true;
			// Google Play services was not available for some reason
		} else {
			// Get the error code
			Log.d("Geofence Detection",
					"Google Play services is NOT available.");
			return false;
		}
	}

	private void gpsManager() {
		this.mLocationRequest = LocationRequest.create();
		this.mLocationRequest
				.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
		this.mLocationRequest.setInterval(Long.MAX_VALUE);
		this.mLocationRequest.setFastestInterval(Long.MAX_VALUE);

		this.mLocationClient = new LocationClient(this, this, this);
		this.checkLocationProvider();

		ConnectivityManager connectivityManager = (ConnectivityManager) this
				.getSystemService(Context.CONNECTIVITY_SERVICE);
		NetworkInfo activeNetworkInfo = connectivityManager
				.getActiveNetworkInfo();
		this.mConnected = activeNetworkInfo != null
				&& activeNetworkInfo.isConnected();
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {

		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// Handle action bar item clicks here. The action bar will
		// automatically handle clicks on the Home/Up button, so long
		// as you specify a parent activity in AndroidManifest.xml.
		int id = item.getItemId();
		if (id == R.id.action_settings) {
			return true;
		}
		return super.onOptionsItemSelected(item);
	}

	/**
	 * A placeholder fragment containing a simple view.
	 */
	public static class PlaceholderFragment extends Fragment {

		public PlaceholderFragment() {
		}

		@Override
		public View onCreateView(LayoutInflater inflater, ViewGroup container,
				Bundle savedInstanceState) {
			View rootView = inflater.inflate(R.layout.fragment_main, container,
					false);
			return rootView;
		}
	}

	@Override
	protected void onStart() {

		this.mLocationClient.connect();

		IntentFilter filterFrag = new IntentFilter();
		filterFrag.addAction(FragmentManagerBroadcast.Action.LOCATION_ACQUIRED);
		LocalBroadcastManager.getInstance(this).registerReceiver(
				mFragmentManagerBroadcast, filterFrag);

		IntentFilter filterBasses = new IntentFilter();
		filterBasses.addAction(PersonalBasesBroadcast.Action.ENTERED_LOCATION);
		LocalBroadcastManager.getInstance(this).registerReceiver(
				mPersonalBasesBroadcast, filterBasses);

		super.onStart();
	}

	@Override
	protected void onStop() {
		super.onStop();
		LocalBroadcastManager.getInstance(this).unregisterReceiver(
				mFragmentManagerBroadcast);
		LocalBroadcastManager.getInstance(this).unregisterReceiver(
				mPersonalBasesBroadcast);

		if (this.mLocationClient.isConnected()) {
			/* Remove location updates for a listener. */
			this.mLocationClient.removeLocationUpdates(this);
		}
		this.mLocationClient.disconnect();
	}

	@Override
	public void onLocationChanged(Location arg0) {

	}

	private void checkLocationProvider() {
		/*
		 * Google Play Services doesn't allow to check if GPS is enabled, so we
		 * have to use the old LocationManager.
		 */
		// LocationManager locationManager = (LocationManager)
		// this.getSystemService(Context.LOCATION_SERVICE);
		// if (!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
		// &&
		// !locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER))
		// {
		// BaseDialogFragment dialog =
		// EnableGeolocationDialogFragment.newInstance();
		// this.showDialog(dialog);
		// }
	}

	@Override
	protected void onDestroy() {
		this.mLocationClient = null;
		this.unregisterReceiver(this.mNetworkReceiver);
		this.mNetworkReceiver = null;
		super.onDestroy();
	}

	@Override
	public void onRemoveGeofencesByPendingIntentResult(int statusCode,
			PendingIntent pendingIntent) {
		// TODO Auto-generated method stub
	}

	@Override
	public void onRemoveGeofencesByRequestIdsResult(int statusCode,
			String[] geofenceRequestIds) {
		// TODO Auto-generated method stub
	}

	@Override
	public void onAddGeofencesResult(int statusCode, String[] geofenceRequestIds) {
		if (LocationStatusCodes.SUCCESS == statusCode) {

			showToast("GeoFence Success", Toast.LENGTH_SHORT);
		} else {
			showToast("GeoFence Failed", Toast.LENGTH_SHORT);
		}
	}

	protected void showToast(final String message, final int duration) {
		new Handler().post(new Runnable() {

			@Override
			public void run() {
				Toast.makeText(getBaseContext(), message, duration).show();
				// TODO Auto-generated method stub

			}
		});
	}

	@Override
	public void onConnectionFailed(ConnectionResult result) {
		try {
			if (result.hasResolution()) {
				result.startResolutionForResult(this,
						CONNECTION_FAILURE_RESOLUTION_REQUEST);
			} else {

			}
		} catch (IntentSender.SendIntentException e) {
			Log.d(TAG, e.getLocalizedMessage());
		}

	}

	@Override
	public void onConnected(Bundle connectionHint) {

		mLocationClient.requestLocationUpdates(mLocationRequest, this);
		mLocation = mLocationClient.getLastLocation();

		setSavedPark(new LatLng(mLocation.getLatitude(),
				mLocation.getLongitude()));
		mMapFrag.getMap().animateCamera(
				CameraUpdateFactory.newLatLngZoom(
						new LatLng(mLocation.getLatitude(), mLocation
								.getLongitude()), 14), 2000, null);
		LatLng center = new LatLng(mLocation.getLatitude(),
				mLocation.getLongitude());
		mMapFrag.getMap().addMarker(
				new MarkerOptions().position(center).draggable(true));

		createGeofences(mLocation);
		addGeofences(mCurrentGeofences);
		// mTransitionPendingIntent = getTransitionPendingIntent();
		// // Send a request to add the current geofences
		// mLocationClient.addGeofences(mCurrentGeofences,
		// mTransitionPendingIntent, this);
	}

	@Override
	public void onDisconnected() {
		// TODO Auto-generated method stub

	}

	/**
	 * Storage for geofence values, implemented in SharedPreferences.
	 */
	public void createGeofences(Location location) {
		/*
		 * Create an internal object to store the data. Set its ID to "1". This
		 * is a "flattened" object that contains a set of strings
		 */
		SimpleGeofence mUIGeofence1 = new SimpleGeofence("1",
				location.getLatitude(), location.getLongitude(), 100, 100000,
				// This geofence records only entry transitions
				Geofence.GEOFENCE_TRANSITION_ENTER, 0);
		// Store this flat version
		mGeofenceStorage.setGeofence("1", mUIGeofence1);
		mCurrentGeofences.add(mUIGeofence1.toGeofence());
	}

	// private PendingIntent getTransitionPendingIntent() {
	// // Create an explicit Intent
	// Intent intent = new Intent(this, ReceiveTransitionsIntentService.class);
	// /*
	// * Return the PendingIntent
	// */
	// return PendingIntent.getService(this, 0, intent,
	// PendingIntent.FLAG_UPDATE_CURRENT);
	// }

	private void addGeofences(List<Geofence> list) {
		PendingIntent mTransitionPendingIntent = createRequestPendingIntent();
		mLocationClient.addGeofences(list, mTransitionPendingIntent, this);
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);

		switch (requestCode) {
		case CONNECTION_FAILURE_RESOLUTION_REQUEST:
			switch (resultCode) {
			case Activity.RESULT_OK:
				// mLocationClient.connect();
				break;

			default:
				break;
			}
			break;

		default:
			break;
		}

	}

	private PendingIntent mGeofencePendingIntent;

	private PendingIntent createRequestPendingIntent() {

		// If the PendingIntent already exists
		if (null != mGeofencePendingIntent) {

			// Return the existing intent
			return mGeofencePendingIntent;

			// If no PendingIntent exists
		} else {

			// Create an Intent pointing to the IntentService
			Intent intent = new Intent(this,
					ReceiveTransitionsIntentService.class);
			/*
			 * Return a PendingIntent to start the IntentService. Always create
			 * a PendingIntent sent to Location Services with
			 * FLAG_UPDATE_CURRENT, so that sending the PendingIntent again
			 * updates the original. Otherwise, Location Services can't match
			 * the PendingIntent to requests made with it.
			 */
			return PendingIntent.getService(this, 0, intent,
					PendingIntent.FLAG_UPDATE_CURRENT);
		}
	}

}
